package com.yzg.cas;

import java.util.LinkedList;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author misterWei
 * @create 2020年05月23号:23点20分
 * @mailbox forcontinue@163.com
 *
 * 2. 无锁方式实现共享变量原子性操作
 */
public class CasVariable2 {

    public static void main(String[] args) {
        Account account = new CasAccount(10000);
        account.test(account);
        System.out.println(account.getAccount());
    }



    interface Account{
        int getAccount();
        void optionAccount(int account);

        default void test(Account account){
            // 测试 1000 并发量
            int threadNum = 1000;

            CyclicBarrier cyclicBarrier = new CyclicBarrier(threadNum);
            LinkedList<Thread> linkedList = new LinkedList();
            for (int i = 0; i < threadNum; i++) {
                Thread thread = new Thread(() -> {
                    try {
                        //模拟并发
                        cyclicBarrier.await();
                        account.optionAccount(10);
                    } catch (InterruptedException | BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }, i + " thread");
                linkedList.addLast(thread);
            }
            linkedList.forEach(thread -> {
                thread.start();
            });
                linkedList.forEach(thread -> {
                    try {
                        thread.join();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });


        }

    }

    /**
     * 带锁方式实现
     */
    static class CasAccount implements Account{
        final AtomicInteger account;

        public CasAccount(int account) {
            this.account = new AtomicInteger(account);
        }

        @Override
        public  int getAccount() {
            return this.account.get();
        }
        @Override
        public  void optionAccount(int account) {
            /**
             * cas 无锁并发的核心点
             */
            //不断进行重试
            while (true){
                //当前最新的值
                int prev =  this.account.get();
                //要更改的值
                int next  =  (prev - account);
                if (this.account.compareAndSet(prev,next)){
                    // 修改成功
                    break;
                }
                /**
                 * compareAndSet 正是做这个检查，在 set 前，先比较 prev 与当前值
                 *  - 不一致了，next 作废，返回 false 表示失败
                 *  比如，别的线程已经做了减法，当前值已经被减成了 990
                 *  那么本线程的这次 990 就作废了，进入 while 下次循环重试
                 *  - 一致，以 next 设置为新值，返回 true 表示成功
                 */
            }
            //简写方式
           // this.account.getAndAdd(-1 * account);
        }
    }

}
